/**
 * 基本信息
 *
 * @format
 */

import { BaseDao, dateFormatter, resultsModel, transformBeijingDate } from '../../sdk'
import { STAT_DB_NAME, ACCESS_DB_NAME, USER_DB_NAME, AWARDS_DB_NAME, JOIN_DB_NAME, MARK_RECORD } from '../../db'
import * as xlsx from 'node-xlsx'
import { getToday } from '../../utils'
import { PRIZE_TYPE, STAT_TYPE } from '../../constants'
import { formatDate } from '../../utils/common/date'

export default class StatService {
  context: IContext<any>
  statdao: IBaseDao
  accessdao: IBaseDao
  userdao: IBaseDao
  awardsdao: IBaseDao
  joindao: IBaseDao
  markdao: IBaseDao
  constructor(context: IContext<IParams>) {
    this.context = context
    this.statdao = new BaseDao(context, STAT_DB_NAME)
    this.accessdao = new BaseDao(context, ACCESS_DB_NAME)
    this.userdao = new BaseDao(context, USER_DB_NAME)
    this.joindao = new BaseDao(context, JOIN_DB_NAME)
    this.awardsdao = new BaseDao(context, AWARDS_DB_NAME)
    this.markdao = new BaseDao(context, MARK_RECORD)
  }

  /**
   *  添加数据统计记录
   *
   * @param {number} type  数据类型
   * @param {object} [customStatData={}] 自定义数据
   * @param {IUserInfo} [userInfo] 用户信息
   * @return {boolean}
   * @memberof StatService
   */
  async addStat(
    type: number | string,
    userInfo: IUserInfo = {} as IUserInfo,
    customStatData: object = {}
  ): Promise<{ id: string }> {
    const { openId } = this.context
    const { activityId } = this.context.data

    const typeName = typeof type === 'string' ? type : STAT_TYPE[type]
    const _type = typeof type === 'string' ? STAT_TYPE[type] : type
    const joinInfo = await this.joindao.findOne({ activityId, openId })
    const id = await this.statdao.insertOne({
      activityId,
      type: _type,
      typeName,
      openId,
      isJoin: joinInfo ? true : false,
      ...customStatData,
      createTime: Date.now(),
      createDay: getToday()
    })
    return { id }
  }

  async getStats(activityInfo: IActivityInfo, startDay: string, endDay: string): Promise<any> {
    const { _id: activityId, probabilityConfig } = activityInfo
    let day = startDay
    const oneDay = 24 * 3600 * 1000
    let xlsxData = []
    let curDayTimestamp = formatDate(day).getTimestamp()
    const endDayTimestamp = formatDate(endDay).getTimestamp()
    while (curDayTimestamp <= endDayTimestamp) {
      // 访问PV
      const PVpromise = this.accessdao.count({ activityId, createDay: day })
      // 访问UV
      const UVpromise = this.userdao.count({ activityId, [`login.${day}`]: { $exists: true } })
      // 新增UV
      const newUVpromise = this.userdao.count({ activityId, createDay: day })

      // 参与PV
      const joinPVpromise = this.joindao.count({ activityId, createDay: day, openId: { $exists: true } })

      // 参与UV
      const joinUVpromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day, openId: { $exists: true } } },
        { $group: { _id: '$openId' } }
      ])

      // statUV
      const statUVPromise = (type, query?) => {
        return new Promise(async (resolve, reject) => {
          const result = await this.statdao.aggregate([
            { $match: query || { activityId, createDay: day, type } },
            { $group: { _id: '$openId' } }
          ])
          resolve(result.length)
        })
      }

      // statUV
      const statPVPromise = (type, query?) => {
        return this.statdao.count(query || { activityId, createDay: day, type })
      }

      // 各阶梯达成UV
      const levelPromise = () => {
        return new Promise(async (resolve, reject) => {
          const map = {}
          for (let i = 0; i < probabilityConfig.length; i++) {
            if (probabilityConfig[i + 1]) {
              map[
                `阶梯${probabilityConfig[i].nowScore}-${probabilityConfig[i + 1].nowScore - 1}达成PV`
              ] = await this.joindao.count({
                openId: { $exists: true },
                activityId,
                createDay: day,
                score: { $lt: +probabilityConfig[i + 1].nowScore, $gte: +probabilityConfig[i].nowScore }
              })
              map[`阶梯${probabilityConfig[i].nowScore}-${probabilityConfig[i + 1].nowScore - 1}达成UV`] = (
                await this.joindao.aggregate([
                  {
                    $match: {
                      activityId,
                      createDay: day,
                      openId: { $exists: true },
                      score: { $lt: +probabilityConfig[i + 1].nowScore, $gte: +probabilityConfig[i].nowScore }
                    }
                  },
                  { $group: { _id: '$openId' } }
                ])
              ).length
            } else {
              map[`阶梯${probabilityConfig[i].nowScore}以上达成PV`] = await this.joindao.count({
                activityId,
                createDay: day,
                openId: { $exists: true },
                score: { $gte: +probabilityConfig[i].nowScore }
              })
              map[`阶梯${probabilityConfig[i].nowScore}以上达成UV`] = (
                await this.joindao.aggregate([
                  {
                    $match: {
                      activityId,
                      createDay: day,
                      openId: { $exists: true },
                      score: { $gte: +probabilityConfig[i].nowScore }
                    }
                  },
                  { $group: { _id: '$openId' } }
                ])
              ).length
            }
          }
          resolve(map)
        })
      }

      // 抽奖PV
      const doLuckPVpromise = this.joindao.count({
        activityId,
        openId: { $exists: true },
        createDay: day,
        isDraw: true
      })

      // 抽奖UV
      const doLuckUVpromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day, isDraw: true, openId: { $exists: true } } },
        { $group: { _id: '$openId' } }
      ])

      // 中奖PV
      const luckPVpromise = this.awardsdao.count({ activityId, type: { $ne: PRIZE_TYPE.THANKS }, createDay: day })

      // 中奖UV
      const luckUVpromise = this.awardsdao.aggregate([
        { $match: { activityId, type: { $ne: PRIZE_TYPE.THANKS }, createDay: day } },
        { $group: { _id: '$openId' } }
      ])

      // 小老虎发放
      const tigerPVpromise = this.awardsdao.count({ activityId, type: PRIZE_TYPE.CARD, createDay: day })

      // 加时卡获得PV
      const getTimePVpromise = this.userdao.aggregate([
        { $match: { activityId, [`taskInfo.${day}.invite`]: { $exists: true } } },
        { $unwind: `$taskInfo.${day}.invite` }
      ])

      // 加时卡获得UV
      const getTimeUVpromise = this.userdao.count({ activityId, [`taskInfo.${day}.invite`]: { $exists: true } })

      // 加时卡使用PV
      const useTimePVpromise = this.joindao.count({
        activityId,
        openId: { $exists: true },
        createDay: day,
        useTimeToolCount: { $gt: 0 }
      })

      // 加时卡使用UV
      const useTimeUVpromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day, openId: { $exists: true }, useTimeToolCount: { $gt: 0 } } },
        { $group: { _id: '$openId' } }
      ])

      // 受邀进入有参与记录UV
      const accessByInviteWithJoinUVpromise = this.statdao.aggregate([
        { $match: { activityId, createDay: day, isJoin: true, type: STAT_TYPE.JOIN_BY_PWD } },
        { $group: { _id: '$openId' } }
      ])

      // 受邀进入未参与记录UV
      const accessByInviteWithNoJoinUVpromise = this.statdao.aggregate([
        { $match: { activityId, createDay: day, isJoin: false, type: STAT_TYPE.JOIN_BY_PWD } },
        { $group: { _id: '$openId' } }
      ])

      // 总停留时长
      const joinDurationSumPromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day } },
        { $group: { _id: null, count: { $sum: '$duration' } } }
      ])

      // 总参与uv
      const joinUVPromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day } },
        { $project: { openId: true } },
        { $group: { _id: '$openId', count: { $sum: 1 } } }
      ])

      // 总完成分数
      const finishJoinScoreSumPromise = this.joindao.aggregate([
        { $match: { activityId, createDay: day, status: { $ne: 1 } } },
        { $group: { _id: null, count: { $sum: '$score' } } }
      ])

      // 总完成pv
      const joinFinishPVPromise = this.joindao.count({ activityId, createDay: day, status: { $ne: 1 } })

      const [
        PV,
        UV,
        newUV,
        joinPV,
        joinUV,
        completeUV,
        doLuckPV,
        doLuckUV,
        luckPV,
        luckUV,
        tigerPV,
        jumpGoodsPV,
        jumpGoodsUV,
        backHomePV,
        backHomeUV,
        clickTimePV,
        clickTimeUV,
        getTimePV,
        getTimeUV,
        useTimePV,
        useTimeUV,
        shareScorePV,
        shareScoreUV,
        shareNormalPV,
        shareNormalUV,
        shareTimePV,
        shareTimeUV,
        totalSharePV,
        totalShareUV,
        totalShareExcludeNomalPV,
        totalShareExcludeNomalUV,
        joinByPwdPV,
        joinByPwdUV,
        level,
        accessByInviteWithJoinUV,
        accessByInviteWithNoJoinUV,
        joinDurationSum,
        finishJoinScoreSum,
        joinFinishPV
      ] = await Promise.all([
        PVpromise,
        UVpromise,
        newUVpromise,
        joinPVpromise,
        joinUVpromise,
        statUVPromise(STAT_TYPE.COMPLETE_GUIDE),
        doLuckPVpromise,
        doLuckUVpromise,
        luckPVpromise,
        luckUVpromise,
        tigerPVpromise,
        statPVPromise(STAT_TYPE.JUMP_PRODUCT),
        statUVPromise(STAT_TYPE.JUMP_PRODUCT),
        statPVPromise(STAT_TYPE.BACK_HOME),
        statUVPromise(STAT_TYPE.BACK_HOME),
        statPVPromise(STAT_TYPE.CLICK_TIME),
        statUVPromise(STAT_TYPE.CLICK_TIME),
        getTimePVpromise,
        getTimeUVpromise,
        useTimePVpromise,
        useTimeUVpromise,
        statPVPromise(STAT_TYPE.SHARE_SCORE),
        statUVPromise(STAT_TYPE.SHARE_SCORE),
        statPVPromise(STAT_TYPE.SHARE_NORMAL),
        statUVPromise(STAT_TYPE.SHARE_NORMAL),
        statPVPromise(STAT_TYPE.SHARE_TIME),
        statUVPromise(STAT_TYPE.SHARE_TIME),
        statPVPromise(STAT_TYPE.SHARE_SCORE, {
          activityId,
          type: { $in: [STAT_TYPE.SHARE_SCORE, STAT_TYPE.SHARE_NORMAL, STAT_TYPE.SHARE_TIME] },
          createDay: day
        }),
        statUVPromise(STAT_TYPE.SHARE_SCORE, {
          activityId,
          type: { $in: [STAT_TYPE.SHARE_SCORE, STAT_TYPE.SHARE_NORMAL, STAT_TYPE.SHARE_TIME] },
          createDay: day
        }),
        statPVPromise(STAT_TYPE.SHARE_SCORE, {
          activityId,
          type: { $in: [STAT_TYPE.SHARE_SCORE, STAT_TYPE.SHARE_TIME] },
          createDay: day
        }),
        statUVPromise(STAT_TYPE.SHARE_SCORE, {
          activityId,
          type: { $in: [STAT_TYPE.SHARE_SCORE, STAT_TYPE.SHARE_TIME] },
          createDay: day
        }),
        statPVPromise(STAT_TYPE.JOIN_BY_PWD),
        statUVPromise(STAT_TYPE.JOIN_BY_PWD),
        levelPromise(),
        accessByInviteWithJoinUVpromise,
        accessByInviteWithNoJoinUVpromise,
        joinDurationSumPromise,
        finishJoinScoreSumPromise,
        joinFinishPVPromise
      ])

      const keyValueMapper = {
        时间: day,
        新增UV: newUV,
        访问PV: PV,
        访问UV: UV,
        参与PV: joinPV,
        参与UV: joinUV.length,
        新手引导通过UV: completeUV,
        ...level,
        抽奖PV: doLuckPV,
        抽奖UV: doLuckUV.length,
        中奖PV: luckPV,
        中奖UV: luckUV.length,
        小老虎发放PV: tigerPV,
        产品墙跳转PV: jumpGoodsPV,
        产品墙跳转UV: jumpGoodsUV,
        返回会员中心PV: backHomePV,
        返回会员中心UV: backHomeUV,
        加时卡点击PV: clickTimePV,
        加时卡点击UV: clickTimeUV,
        加时卡获得PV: getTimePV.length,
        加时卡获得UV: getTimeUV,
        加时卡使用PV: useTimePV,
        加时卡使用UV: useTimeUV.length,
        成绩分享PV: shareScorePV,
        成绩分享UV: shareScoreUV,
        淘宝自带分享PV: shareNormalPV,
        淘宝自带分享UV: shareNormalUV,
        加时卡分享PV: shareTimePV,
        加时卡分享UV: shareTimeUV,
        总分享PV: totalSharePV,
        总分享UV: totalShareUV,
        总分享PV不含自带分享: totalShareExcludeNomalPV,
        总分享UV不含自带分享: totalShareExcludeNomalUV,
        被首次邀请之前参与过UV: accessByInviteWithJoinUV.length,
        被首次邀请之前未参与过UV: accessByInviteWithNoJoinUV.length,
        淘口令进入PV: joinByPwdPV,
        淘口令进入UV: joinByPwdUV,
        平均停留时长: (joinDurationSum?.[0]?.count || 0) / 1000 / joinUV.length,
        平均分数: (finishJoinScoreSum?.[0]?.count || 0) / joinFinishPV
      }
      console.log('keyValueMapper::::::::::', keyValueMapper)

      if (day === startDay) {
        xlsxData.push(Object.keys(keyValueMapper))
      }
      // @ts-ignore
      xlsxData.push(Object.values(keyValueMapper))
      const tommorrow = formatDate(day).getStartTimestamp() + oneDay
      curDayTimestamp = tommorrow
      day = dateFormatter(transformBeijingDate(tommorrow), 'yyyy/MM/dd')
    }
    console.log('xlsxData：：：：：：：：：：', xlsxData)

    return xlsxData
  }

  async exportMarkStats(source) {
    const markList = await this.markdao.aggregate([
      { $match: { source } },
      { $group: { _id: {
        openId: '$openId',
        shopId: '$shopId',
        itemId: '$itemId'
      }, createTime: { $min: '$createTime' } } }
    ])

    let exportList = [['openId','itemId','shopId','createTime']]
    for (let index = 0; index < markList.length; index++) {
      const element = markList[index];
      exportList.push([element?._id?.openId,element?._id?.itemId,element?._id?.shopId,element?.createTime])
    }

    console.log(exportList.length)
    let buffer = xlsx.build([
      {
        name: `数据统计埋点${Date.now()}`,
        data: exportList
      }
    ])

    let result = await this.context.cloud.file.uploadFile({
      fileContent: buffer,
      fileName: `数据统计埋点${Date.now()}.xlsx`
    })
    if (result.url) {
      result.url = result.url?.startsWith('https')
        ? result.url.replace('-internal', '')
        : result.url.replace('http', 'https').replace('-internal', '')
    }
    return result
  }

  async buildExcel(startDay: string, endDay: string, xlsxData: []) {
    let buffer = xlsx.build([
      {
        name: `数据统计${startDay.replace(/\//g, '-')}-${endDay.replace(/\//g, '-')}`,
        data: xlsxData
      }
    ])

    let result = await this.context.cloud.file.uploadFile({
      fileContent: buffer,
      fileName: `数据统计${startDay.replace(/\//g, '-')}-${endDay.replace(/\//g, '-')}.xlsx`
    })
    if (result.url) {
      result.url = result.url?.startsWith('https')
        ? result.url.replace('-internal', '')
        : result.url.replace('http', 'https').replace('-internal', '')
    }
    return result
  }

  async getStatCountByquery(query: IMongoQuery) {
    return await this.statdao.count(query)
  }
}
